package concurrent.executors;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.logging.Logger;
import utils.Log;

public class MonitorThreadPool extends ThreadPoolExecutor {
  private static final String TAG = "MonitorThreadPool-";

  private final ThreadLocal<Long> startTime = new ThreadLocal<Long>();
  private final Logger log = Logger.getAnonymousLogger();
  private final AtomicLong numTasks = new AtomicLong();
  private final AtomicLong totalTime = new AtomicLong();
  private AtomicInteger mCount = new AtomicInteger(1);

  public MonitorThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,
      BlockingQueue<Runnable> workQueue) {
    super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
    setThreadFactory(null);
  }

  @Override
  public void setThreadFactory(ThreadFactory threadFactory) {
    super.setThreadFactory(new ThreadFactory() {
      @Override
      public Thread newThread(Runnable r) {
        java.lang.Thread thread = new java.lang.Thread(r, "task-runner-count");
        try {
          thread.setName(TAG + mCount.getAndIncrement());
        } catch (NoSuchMethodError error) {
          error.printStackTrace();
        }

        return thread;
      }
    });
  }

  @Override
  protected void beforeExecute(Thread t, Runnable r) {
    Log.vn(String.format("Thread %s: start %s", t, r));
    startTime.set(System.nanoTime());
  }

  @Override
  protected void afterExecute(Runnable r, Throwable t) {
    try {
      long endTime = System.nanoTime();
      long taskTime = endTime - startTime.get();
      numTasks.incrementAndGet();
      totalTime.addAndGet(taskTime);
      Log.vn(String.format("Thread %s: end %s, time=%dns", t, r, taskTime));
      if (t != null) {
        Log.vn("=========================");
      }
    } finally {

    }
  }

  @Override
  protected void terminated() {
    try {
      Log.vn(String.format("Terminated: avg time=%dns", totalTime.get() / numTasks.get()));
    } finally {
      super.terminated();
    }
  }
}
